package com.example.base_model.ext

import com.blankj.utilcode.util.LogUtils
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import java.io.IOException
import java.lang.reflect.Type

/**
 * @Author jiangKunKun
 * @CreateDate 2025/7/29
 * @Description Moshi 的扩展函数，用于简化 JSON 的序列化和反序列化操作。
 * 提供了 reified (具体化) 和非 reified 泛型版本，以适应不同的使用场景。
 * @SpittingGrooves
 */

/**
 * 将给定的 [value] 序列化为其 JSON 字符串表示形式。
 *
 * 这是 Kotlin 的 reified 泛型版本，因其易用性而成为最常用的版本。
 * 由于 `T` 是 reified，编译器能够在运行时知道 `T` 的确切类型，
 * 让你能够进行简洁的调用：`moshi.toJson(myObject)`。
 *
 * @param T 要序列化的对象的类型。
 * @param value 要序列化的对象。如果为 null，则此函数返回 null。
 * @param type （可选）要序列化的对象的具体 `java.lang.reflect.Type`。
 *             默认为 `T::class.java`。对于简单类型（如 `User`），此默认值即可。
 *             **但在序列化复杂的泛型类型（如 `List<User>`）时，必须提供此参数**，
 *             因为 `T::class.java` 会变成 `List::class.java`，丢失了元素类型 `User` 的信息。
 *             在这种情况下，需要使用 `com.squareup.moshi.Types.newParameterizedType()` 来创建正确的 `Type`。
 *             **示例**:
 *             ```
 *             val type = Types.newParameterizedType(List::class.java, User::class.java)
 *             moshi.toJson(userList, type)
 *             ```
 * @param indent （可选）如果为 `true`，输出的 JSON 字符串将被美化（带有 "  " 缩进）。
 *               默认为 `true`，以方便调试和阅读。对于生产环境或需要紧凑的 JSON，请设置为 `false`。
 * @return 对象的 JSON 字符串表示；如果输入值为 null，则返回 null。
 * @throws com.squareup.moshi.JsonDataException 如果 [value] 无法被序列化（例如，类型不匹配或没有合适的适配器）。
 */
inline fun <reified T> Moshi.toJson(
    value: T?,
    type: Type = T::class.java, // 默认为 T 的 Class，但允许覆盖以处理泛型
    indent: Boolean = true
): String? {
    if (value == null) return null

    // 1. 根据指定的 type 获取对应的 JsonAdapter。
    //    对于 reified T，如果 type 未被显式提供，T::class.java 会被用作默认值。
    //    这对于非泛型类工作得很好。但对于 List<String> 等，必须显式传递一个 ParameterizedType。
    val adapter: JsonAdapter<T> = this.adapter(type)

    // 2. 根据 indent 参数决定是否格式化输出。
    return if (indent) {
        adapter.indent("  ").toJson(value) // 使用缩进格式化 JSON
    } else {
        adapter.toJson(value) // 输出紧凑的 JSON
    }
}

/**
 * `toJson` 的非 reified (非具体化) 泛型重载版本。
 *
 * 当泛型类型 `T` 在编译时未知，而是通过一个 `Class<T>` 对象在运行时确定时，此版本非常有用。
 *
 * **注意**: 此版本在处理泛型集合时有局限性。例如，如果你传递 `List.class` 作为 `valueType`，
 * Moshi 将不知道列表元素的具体类型，可能会导致序列化为 `List<Map<String, Any>>` 而不是 `List<User>`。
 * 对于泛型，强烈建议使用 reified 版本或接受 `java.lang.reflect.Type` 的版本。
 *
 * @param T 要序列化的对象的类型。
 * @param value 要序列化的对象。如果为 null，则此函数返回 null。
 * @param valueType 要序列化对象的 `Class` 类型。这是必需的，因为 `T` 不是 reified。
 * @param indent （可选）如果为 `true`，输出的 JSON 字符串将被美化。默认为 `true`。
 * @return 对象的 JSON 字符串表示；如果输入值为 null，则返回 null。
 * @throws com.squareup.moshi.JsonDataException 如果 [value] 无法被序列化。
 */
fun <T> Moshi.toJson(
    value: T?,
    valueType: Class<T>, // 明确传递 Class<T>
    indent: Boolean = true
): String? {
    if (value == null) return null
    val adapter: JsonAdapter<T> = this.adapter(valueType)
    return if (indent) {
        adapter.indent("  ").toJson(value)
    } else {
        adapter.toJson(value)
    }
}

/**
 * 将给定的 JSON 字符串 [jsonString] 反序列化为类型为 `T` 的对象。
 *
 * 这是 Kotlin 的 reified 泛型版本，因其类型安全和简洁性而成为最常用的版本。
 * 函数内部处理了 `IOException` 和 `JsonDataException`，并在发生错误时返回 `null`，使调用更安全。
 *
 * **示例**:
 * ```
 * // 反序列化简单对象
 * val user: User? = moshi.fromJson<User>(jsonString)
 *
 * // 反序列化泛型列表
 * val type = Types.newParameterizedType(List::class.java, User::class.java)
 * val userList: List<User>? = moshi.fromJson(jsonString, type)
 * ```
 *
 * @param T 目标对象的类型。
 * @param jsonString 要反序列化的 JSON 字符串。如果为 null 或空白，则此函数返回 null。
 * @param type （可选）要反序列化成的具体 `java.lang.reflect.Type`。
 *             默认为 `T::class.java`。与 `toJson` 类似，在反序列化为复杂泛型类型时必须提供此参数。
 * @return 反序列化后的对象；如果 JSON 字符串为 null/空白，或反序列化失败，则返回 `null`。
 *         失败时会通过 `LogUtils.d` 记录错误日志。
 */
inline fun <reified T> Moshi.fromJson(
    jsonString: String?,
    type: Type = T::class.java // 允许在需要时指定更复杂的类型
): T? {
    if (jsonString.isNullOrBlank()) return null
    // 1. 获取对应类型的 JsonAdapter
    val adapter: JsonAdapter<T> = this.adapter(type)
    return try {
        // 2. 尝试反序列化
        adapter.fromJson(jsonString)
    } catch (e: IOException) {
        // 3a. 当发生底层 I/O 问题时捕获（例如，从损坏的流中读取）
        LogUtils.d("Moshi.fromJson IO 错误: ${e.message}", e)
        null
    } catch (e: com.squareup.moshi.JsonDataException) {
        // 3b. 当 JSON 数据与期望的类型不匹配时捕获（例如，字段缺失、类型错误）
        LogUtils.d("Moshi.fromJson JSON 数据错误: ${e.message}", e)
        null
    }
}

/**
 * `fromJson` 的非 reified (非具体化) 泛型重载版本。
 *
 * 当目标类型 `T` 在编译时未知，而是通过 `Class<T>` 对象在运行时确定时使用。
 *
 * **注意**: 此版本无法直接反序列化为泛型类型。例如，调用 `moshi.fromJson(json, List.class)`
 * 会返回一个 `List<Map<String, Any>>`，而不是你可能期望的 `List<User>`。
 * 对于泛型，请使用 reified 版本并提供一个 `Type`。
 *
 * @param T 目标对象的类型。
 * @param jsonString 要反序列化的 JSON 字符串。
 * @param valueType 目标对象的 `Class` 类型。
 * @return 反序列化后的对象；如果 JSON 字符串为 null/空白，或反序列化失败，则返回 `null`。
 */
fun <T> Moshi.fromJson(
    jsonString: String?,
    valueType: Class<T> // 明确传递 Class<T>
): T? {
    if (jsonString.isNullOrBlank()) return null
    val adapter: JsonAdapter<T> = this.adapter(valueType)
    return try {
        adapter.fromJson(jsonString)
    } catch (e: IOException) {
        LogUtils.d("Moshi.fromJson IO 错误: ${e.message}", e)
        null
    } catch (e: com.squareup.moshi.JsonDataException) {
        LogUtils.d("Moshi.fromJson JSON 数据错误: ${e.message}", e)
        null
    }
}
